{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "File operations are one of the most common uses of context managers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Don't forget to subscribe to ArjanCodes ;).\n"
     ]
    }
   ],
   "source": [
    "with open(\"example.txt\", \"r\") as file:\n",
    "    content = file.read()\n",
    "    print(content)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Context managers can help manage external connections like databases, ensuring they close properly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(1, 'Alice'), (1, 'Alice'), (1, 'Alice')]\n"
     ]
    }
   ],
   "source": [
    "import sqlite3\n",
    "\n",
    "with sqlite3.connect(\"example.db\") as conn:\n",
    "    cursor = conn.cursor()\n",
    "    cursor.execute(\"CREATE TABLE IF NOT EXISTS users (id INTEGER, name TEXT)\")\n",
    "    cursor.execute(\"INSERT INTO users (id, name) VALUES (1, 'Alice')\")\n",
    "    conn.commit()\n",
    "    cursor.execute(\"SELECT * FROM users\")\n",
    "    print(cursor.fetchall())\n",
    "# The connection is automatically closed at the end of the block."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can create your own context manager using generators with `@contextmanager`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sum computed: 49999995000000\n",
      "Elapsed time: 0.13 seconds\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "from contextlib import contextmanager\n",
    "\n",
    "\n",
    "@contextmanager\n",
    "def timer():\n",
    "    start = time.time()\n",
    "    yield\n",
    "    end = time.time()\n",
    "    print(f\"Elapsed time: {end - start:.2f} seconds\")\n",
    "\n",
    "\n",
    "# Usage:\n",
    "with timer():\n",
    "    total = sum(range(10_000_000))\n",
    "    print(f\"Sum computed: {total}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For more complex scenarios, implement the `__enter__` and `__exit__` methods directly in a class."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Resource acquired\n",
      "Using the resource\n",
      "Resource released\n"
     ]
    }
   ],
   "source": [
    "class CustomResource:\n",
    "    def __enter__(self):\n",
    "        print(\"Resource acquired\")\n",
    "        return self\n",
    "\n",
    "    def __exit__(self, exc_type, exc_value, traceback):\n",
    "        print(\"Resource released\")\n",
    "\n",
    "\n",
    "with CustomResource() as resource:\n",
    "    print(\"Using the resource\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
